﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GestorSQL.BusinessEntities;
using GestorSQL.DAO;
using GestorSQL.DAO.FileManager;
using GestorSQL.BLL.ImplementationsBridge;
using GestorSQL.BLL.QueryExecutions;
using System.Threading;
using AspectIntercept;
using GestorSQL.DAO.InterceptDAO;

namespace GestorSQL.BLL
{
    [Intercept(InterceptAllMethods = true, PreProcesor = typeof(DBTraceProcessor), PostProcesor = typeof(DBTraceProcessor), OmitMethods = new string[] { })]
    public class CaseManager : InterceptContext
    {
        #region Variables privadas
        private Caso _case;
        private bool _isDirty = false;
        private bool _isAuthorizationCase = false;
        private IGestorSqlDao dao = new GestorSqlDao();
        #endregion

        #region Propiedades
        /// <summary>
        /// Obtiene la sentencia sql del caso
        /// </summary>
        [InterceptOmit]
        public string Statement
        {
            get { return _case.QueryActual; }
            set
            {
                if (_case.QueryActual != null && !_case.QueryActual.Equals(value.Trim()))
                    _isDirty = true;
                _case.QueryActual = value.Trim();
            }
        }

        /// <summary>
        /// Retorna true si el texto de la sentencia ha cambiado y no ha sido guardado, de lo contrario false
        /// </summary>
        [InterceptOmit]
        public bool IsDirty { get { return _isDirty; } }

        /// <summary>
        /// Obtiene el estado actual del casos
        /// </summary>
        [InterceptOmit]
        public EstadoCaso CaseState { get { return _case.Historia.Estado_; } }

        /// <summary>
        /// Obtiene el estado actual del casos
        /// </summary>
        [InterceptOmit]
        public bool IsAuthorization { get { return _isAuthorizationCase; } set { _isAuthorizationCase = value; } }

        /// <summary>
        /// Determina si existe o no una conexion asociada para ejecucion
        /// </summary>
        [InterceptOmit]
        public bool HasConnection { get { if (Connection == null) return false; return true; } }

        /// <summary>
        /// Obtiene la conexion segun el estado en el que se encuentre
        /// </summary>
        [InterceptOmit]
        public Conexion Connection
        {
            get
            {
                switch (CaseState)
                {
                    case EstadoCaso.DevueltoDesdeAutorizacion:
                    case EstadoCaso.Creado:
                    case EstadoCaso.Abierto:
                    case EstadoCaso.Guardado:
                        return _case.Conexion;
                    case EstadoCaso.Resuelto:
                    case EstadoCaso.AutorizadoAutomatico:
                    case EstadoCaso.AutorizadoAsistido:
                        return _case.Conexion1;
                    case EstadoCaso.DevueltoDesdeEjecucion:
                    case EstadoCaso.EjecutadoCorrectamente:
                    case EstadoCaso.EjecutadoError:
                    default:
                        return null;
                }
            }
        }

        /// <summary>
        /// Obtiene el numero del caso
        /// </summary>
        [InterceptOmit]
        public string CaseNumber { get { return _case.NumeroCaso; } }

        /// <summary>
        /// Obtiene el caso actual 
        /// </summary>
        public Caso CurrentCase { get { return _case; } }

        /// <summary>
        /// Determina si es un caso a ejecutar en ambiente de producción.
        /// Es decir esta en estado Autorizado Asistido
        /// </summary>
        /// <param name="caseNumber"></param>
        /// <returns></returns>
        public Resultado CasoParaEjecutarEnProduccion
        {
            get
            {
                if ((_case.Historia.Estado == (long)EstadoCaso.AutorizadoAsistido))
                {
                    if (DateTime.Now >= _case.Solucion.FechaInicio && DateTime.Now <= _case.Solucion.FechaFin)
                        return Resultado.Exitoso;
                    else
                        return Resultado.FechaInvalida;
                }
                else
                    return Resultado.Fallido;
            }
        }

        #endregion

        #region Metodos Publicos
        /// <summary>
        /// Crea un nuevo caso
        /// </summary>
        /// <param name="caseNumber">Numero del Caso</param>
        /// <param name="analystUserId">Usuario Analista</param>
        /// <param name="ownerUserId">Usuario Dueño del caso</param>
        public void StartCase(string caseNumber, string analystUserId, string ownerUserId)
        {
            Historia estado = new Historia()
            {
                Descripcion = "Creación de caso",
                Fecha = dao.GetDataBaseDateTime(),
                Estado_ = EstadoCaso.Creado
            };
            _case = new Caso()
            {
                NumeroCaso = caseNumber,
                UsuarioPruebas = analystUserId,
                UsuarioDueno = ownerUserId,
                UsuarioProduccion = string.Empty,
                QueryActual = string.Empty
            };
            _case.Historia = estado;
            dao.CreateCase(_case);
        }

        /// <summary>
        /// Obtiene la lista de casos de un usuairo
        /// </summary>
        /// <param name="userId">Id Usuario</param>
        /// <param name="roles">Roles del Usuario</param>
        /// <returns></returns>
        [InterceptOmit]
        public List<Caso> GetCaseList(string userId, string[] roles)
        {
            return dao.GetCaseListByUserNameAndRoles(userId, roles);
        }

        /// <summary>
        /// Abre un caso
        /// </summary>
        /// <param name="caseNumber">Numero del caso</param>
        /// <param name="analystUserId">Usuario analista</param>
        public void OpenCase(string caseNumber, string analystUserId)
        {
            _case = dao.GetCase(caseNumber);

            IFileManager fileManager = ImplementationBridge.GetFileManager("Compress");

            if (CasoParaEjecutarEnProduccion == Resultado.Exitoso)
            {
                SolutionManager _solutionManager = new SolutionManager();
                this.Statement = _solutionManager.GetOriginalSolution(caseNumber, _case.SolucionActual.Value);
            }
            else 
                this.Statement = fileManager.GetFileData(PathGetter.GetDevPath(_case), PathGetter.CURRENT);
            _isDirty = false;
        }

        /// <summary>
        /// Guarda el caso actual
        /// <param name="saveQuery">True si desea guardar el query actual</param>
        /// </summary>
        public void SaveCase(bool saveQuery)
        {
            dao.SaveCase(_case);

            if (saveQuery && _isDirty)
            {
                IFileManager fileManager = ImplementationBridge.GetFileManager("Compress");
                fileManager.SaveFile(PathGetter.GetDevPath(_case), PathGetter.CURRENT, this.Statement, true);
                _isDirty = false;
            }
        }

        /// <summary>
        /// Registra la solución del caso asignado el usuario autorizador
        /// </summary>
        /// <param name="usuarioAutorizador"></param>
        public Resultado ResolveCase(string caseNumber, string usuarioAutorizador, string descripcion, long solucionActual, int idConexionProduccion)
        {
            try
            {
                OpenCase(caseNumber, Thread.CurrentPrincipal.Identity.Name);

                _case.UsuarioAutorizador = usuarioAutorizador;
                _case.Solucion = new Solucion() { IdSolucion = solucionActual };
                _case.Conexion1 = new Conexion() { IdConexion = idConexionProduccion };

                dao.SaveCase(_case);

                return SetStateCase(_case, descripcion, EstadoCaso.Resuelto);
            }
            catch
            {
                return Resultado.Fallido;
            }
        }

        /// <summary>
        /// Asigna la conexion al caso
        /// </summary>
        /// <param name="conn">Conexion</param>
        /// <param name="environment"> Ambiente</param>
        public void SetConnection(Conexion conn, Ambiente environment)
        {
            if (environment == Ambiente.Desarrollo || environment == Ambiente.Pruebas)
            {
                _case.Conexion = conn;
                dao.SaveCase(_case);
            }
            else
                _case.Conexion1 = conn;

        }

        /// <summary>
        /// Establece un nuevo estado actual del caso 
        /// </summary>
        /// <param name="caso"></param>
        /// <param name="descripcion"></param>
        /// <param name="estado"></param>
        /// <returns></returns>
        [InterceptOmit]
        public Resultado SetStateCase(Caso caso, string descripcion, EstadoCaso estado)
        {

            dao.SetCaseState(caso.NumeroCaso, new Historia()
            {
                Descripcion = descripcion,
                Fecha = dao.GetDataBaseDateTime(),
                Estado_ = estado
            });

            return Resultado.Exitoso;
        }

        /// <summary>
        /// Obtiene un caso de acuerdo su numero de identificación
        /// </summary>
        /// <param name="caseNumber"></param>
        /// <returns></returns>
        [InterceptOmit]
        public Caso GetCase(string caseNumber)
        {
            return dao.GetCase(caseNumber);

        }

        /// <summary>
        /// Determina si en un caso para autorización
        /// </summary>
        /// <param name="caseNumber"></param>
        /// <returns></returns>
        public bool CasoParaAutorizar(string caseNumber)
        {

            Caso currentCase = GetCase(caseNumber);

            if ((currentCase.Historia.Estado == (long)EstadoCaso.Resuelto) ||
                (currentCase.Historia.Estado == (long)EstadoCaso.DevueltoDesdeEjecucion) ||
                (currentCase.Historia.Estado == (long)EstadoCaso.EjecutadoError))

                return true;
            else
                return false;

        }

        public List<ConsultaCaso> ViewCasesByParameters(string caseNumber, string usuarioAnalista, string usuarioDueño, DateTime? fechaInicio, DateTime? fechaFin,bool soloEjecucionesAsistidas)
        {
            return dao.ViewCasesByParameters(caseNumber, usuarioAnalista, usuarioDueño, fechaInicio, fechaFin, soloEjecucionesAsistidas);
        }

        /// <summary>
        /// Crea un BLLCommand para el caso actual
        /// </summary>
        /// <returns></returns>
        [InterceptOmit]
        public BLLCommand CreateBLLCommand()
        {
            return new BLLCommand(_case);
        }
        #endregion
    }
}
